﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.FxCop.Sdk;
using System.Reflection;

namespace LINQtoFxCop.Core
{
  /// <summary>
  /// Base LINQ to FxCop introspection rule. Every rule class should inherit from this class directly or indirectly.
  /// </summary>
  public abstract class CoreIntrospectionRule : BaseIntrospectionRule
  {
    protected CoreIntrospectionRule(string ruleName, string resourceName, Assembly assembly)
      : base(ruleName, resourceName, assembly)
    { }
    public override void BeforeAnalysis()
    {
      Problems.Clear();
      AnalysisController.Instance.RuleAnalysisStarting();
    }
    public override ProblemCollection Check(ModuleNode module)
    {
      if (module.NodeType == NodeType.Assembly)
        AnalysisController.Instance.AddContent(module);
      return null;
    }
    public override void AfterAnalysis()
    {
      AnalysisController.Instance.RuleAnalysisFinishing();
      ExecuteQuery();
      AnalysisController.Instance.AddProblems(Name, Problems);
    }

    private void ExecuteQuery()
    {
      //query results are sorted and added to warning report
      Query()
        .OrderByDescending(result => result.Value)
        .ThenBy(result => result.Name)
        .ForEach(result => AddProblem(result.Value, result.Name, result.FullName, result.Node.NodeType));
    }

    protected virtual void AddProblem(Problem problem)
    {
      Problems.Add(problem);
    }
    protected virtual void AddProblem(params object[] args)
    {
      var problem = new Problem(GetResolution(args));
      AddProblem(problem);
    }


    protected virtual QueryResult Result(Node node)
    {
      return Result(node, string.Empty);
    }
    protected virtual QueryResult Result(Node node, IComparable value)
    {
      if(node is EventNode)
        return new QueryResult(value, (node as EventNode).FullName, node);
      return new QueryResult(value, node.ToString(), node);
    }

    protected abstract IEnumerable<QueryResult> Query();


    #region properties
    protected static ApplicationNode Application
    {
      get { return AnalysisController.Instance.Application; }
    }
    protected static IEnumerable<AssemblyNode> Assemblies
    {
      get { return Application.Assemblies; }
    }
    protected static IEnumerable<Namespace> Namespaces
    {
      get { return Application.Namespaces; }
    }
    protected static IEnumerable<TypeNode> Types
    {
      get { return Application.Types; }
    }
    protected static IEnumerable<InterfaceNode> Interfaces
    {
      get { return Types.OfType<InterfaceNode>(); }
    }
    protected static IEnumerable<ClassNode> Classes
    {
      get { return Types.OfType<ClassNode>(); }
    }
    protected static IEnumerable<EnumNode> Enums
    {
      get { return Types.OfType<EnumNode>(); }
    }
    protected static IEnumerable<EventNode> Events
    {
      get { return Application.Members.OfType<EventNode>(); }
    }
    protected static IEnumerable<Method> Methods
    {
      get { return Application.Members.OfType<Method>(); }
    }
    protected static IEnumerable<Field> Fields
    {
      get { return Application.Fields; }
    }
    protected static IEnumerable<PropertyNode> Properties
    {
      get { return Application.Members.OfType<PropertyNode>(); }
    }
    #endregion
  }
}
